package com.sz.app.oss.api;

import com.sz.app.oss.constants.MessagesCodes;
import com.sz.app.oss.exception.ErrorCodes;
import com.sz.biz.app.dto.LoginDataDto;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.i18n.I18nMessages;
import io.swagger.annotations.Api;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Base64;

/**
 * Function: VCodeController <br>
 * Author: Charles <br>
 * Date: 2016-11-16 17:28:00
 */
@Controller
@RequestMapping("/api/v1/auth")
@Api(description = " ", tags = "000-0、安全登录")
public class VCodeController {

    private static final String VCODE_KEY = "checkcode";
    public static final String TEXT_BASE64 = "text/base64";
    public static final String UTF_8 = "UTF-8";
    public static final String JPG = "jpg";

    @Autowired
    protected I18nMessages messageSource;

    private static final int CHECK_CODE_OFFSET = 2;

    @RequestMapping(value = "/login/getcodeimage", method = RequestMethod.GET)
    public void getCodeImage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        //将随机数存在session中
        int random = generateNewRandom();

        InputStream streamBg = null;
        InputStream streamLogo = null;
        try {
            streamBg = this.getClass().getResourceAsStream("/img/code_bg.png");
            streamLogo = this.getClass().getResourceAsStream("/img/code_logo.png");
            BufferedImage bi = VCodeGenerator.mergePic(streamBg, streamLogo, random, 30);

            //设置响应头控制浏览器不要缓存
            response.setDateHeader("expries", -1);
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");

            String accept = request.getHeader("Accept");
            if (TEXT_BASE64.equalsIgnoreCase(accept)) {
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                OutputStream b64 = Base64.getEncoder().wrap(os);
                ImageIO.write(bi, JPG, b64);
                String result = os.toString(UTF_8);

                response.setContentType(TEXT_BASE64);
                response.getWriter().write(result);
                response.flushBuffer();
            } else {
                //设置响应头通知浏览器以图片的形式打开
                response.setContentType("image/jpeg");
                //将图片流写给浏览器
                ImageIO.write(bi, "jpg", response.getOutputStream());
            }
        } finally {
            if (streamBg != null) {
                streamBg.close();
            }
            if (streamLogo != null) {
                streamLogo.close();
            }
        }
    }

    @RequestMapping(value = "/login/checkcodeimage", method = RequestMethod.POST)
    public
    @ResponseBody
    ResultDto checkCodeImage(@RequestBody LoginDataDto loginDataDto)
            throws ServletException, IOException {
        String validateCode = loginDataDto.getValidateCode();
        if (checkVCode(Integer.parseInt(validateCode))) {
            return new ResultDto(0, messageSource.getMessage(MessagesCodes.SUCCESSFUL_VALIDATE_CODE, null));
        }
        generateNewRandom(); //refresh server side v code
        return ResultDto.createResult(ErrorCodes.ERROR_LOGIN_VALIDATE_CODE_ERR);
    }

    /**
     * @param clientVCode
     * @return
     */
    public static synchronized boolean checkVCode(int clientVCode) {
        int serverVCode = VCodeGenerator.genRandomNum(); //init as a random code
        Object random = SecurityUtils.getSubject().getSession().getAttribute(VCODE_KEY);
        if (random != null) {
            serverVCode = Integer.parseInt(random.toString());
        }
        return (clientVCode <= (serverVCode + CHECK_CODE_OFFSET))
                && (clientVCode >= (serverVCode - CHECK_CODE_OFFSET));
    }

    static synchronized int generateNewRandom() {
        int random = VCodeGenerator.genRandomNum();
        SecurityUtils.getSubject().getSession().setAttribute(VCODE_KEY, random);
        return random;
    }
}
